﻿using System;
using System.Windows.Input;

namespace Base.Core
{
    public class DelegateCommand : ICommand
    {
        private Action<object> _action;
        private Func<object, bool> _canExecute;

        public event EventHandler CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        public DelegateCommand(Action<object> action) : this(action, null)
        {

        }

        public DelegateCommand(Action<object> action, Func<object, bool> canExecute)
        {
            _action = action;
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute?.Invoke(parameter) ?? true;
        }

        public void Execute(object parameter)
        {
            _action?.Invoke(parameter);
        }
    }


    public class DelegateCommand<T> : ICommand
    {
        private Action<T> _action;
        private Func<T, bool> _canExecute;
        private Func<bool> _canExecuteNp;

        public event EventHandler CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
            }
            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        public DelegateCommand(Action<T> action)
        {
            _action = action;
        }

        public DelegateCommand(Action<T> action, Func<T, bool> canExecute)
        {
            _action = action;
            _canExecute = canExecute;
        }

        public DelegateCommand(Action<T> action, Func<bool> canExecuteNp)
        {
            _action = action;
            _canExecuteNp = canExecuteNp;
        }

        bool ICommand.CanExecute(object parameter)
        {
            if (parameter == null)
                return CanExecute(default(T));

            return CanExecute((T)parameter);
        }

        void ICommand.Execute(object parameter)
        {
            if (parameter == null)
                Execute(default(T));
            else
                Execute((T)parameter);
        }

        public bool CanExecute(T parameter)
        {
            if (_canExecute != null)
                return _canExecute.Invoke(parameter);
            if (_canExecuteNp != null)
                return _canExecuteNp.Invoke();

            return true;
        }

        public void Execute(T parameter)
        {
            _action?.Invoke(parameter);
        }
    }
}
